#include "cpu.h"
#include "mmu.h"

byte regs8[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
word regs16[2] = { 0, 0 };

FILE* rom;

int main(int argc, byte *argv[])
{
	mmu_init();
	//TODO: fetch
	byte opcode = 0;
	while (opcode != 0x10) {
		dispatch(opcode = rb(regs16[PC]++));
	}
 	system("PAUSE");
 	return 0;
}

void dispatch(byte op) {
	switch (op) {
		case 0x00: nop(); break;
		case 0x01: LD_reg16_lit(BC); break;
		
		case 0x06: LD_reg_lit(B); break;
		
		case 0x0E: LD_reg_lit(C); break;
		
		case 0x11: LD_reg16_lit(DE); break;
		
		case 0x16: LD_reg_lit(D); break;
		
		case 0x1E: LD_reg_lit(E); break;
		
		case 0x21: LD_reg16_lit(HL); break;
		
		case 0x26: LD_reg_lit(H); break;
		
		case 0x2E: LD_reg_lit(L); break;
		
		case 0x31: LD_reg16_lit(SP); break;
		
		case 0x3E: LD_reg_lit(A); break;
		
		case 0x40: LD_reg_reg(B, B); break;
		case 0x41: LD_reg_reg(B, C); break;
		case 0x42: LD_reg_reg(B, D); break;
		case 0x43: LD_reg_reg(B, E); break;
		case 0x44: LD_reg_reg(B, H); break;
		case 0x45: LD_reg_reg(B, L); break;
		case 0x46: LD_reg_HLm(B); break;
		case 0x47: LD_reg_reg(B, A); break;
		case 0x48: LD_reg_reg(C, B); break;
		case 0x49: LD_reg_reg(C, C); break;
		case 0x4A: LD_reg_reg(C, D); break;
		case 0x4B: LD_reg_reg(C, E); break;
		case 0x4C: LD_reg_reg(C, H); break;
		case 0x4D: LD_reg_reg(C, L); break;
		case 0x4E: LD_reg_HLm(C); break;
		case 0x4F: LD_reg_reg(C, A); break;
		case 0x50: LD_reg_reg(D, B); break;
		case 0x51: LD_reg_reg(D, C); break;
		case 0x52: LD_reg_reg(D, D); break;
		case 0x53: LD_reg_reg(D, E); break;
		case 0x54: LD_reg_reg(D, H); break;
		case 0x55: LD_reg_reg(D, L); break;
		case 0x56: LD_reg_HLm(D); break;
		case 0x57: LD_reg_reg(D, A); break;
		case 0x58: LD_reg_reg(E, B); break;
		case 0x59: LD_reg_reg(E, C); break;
		case 0x5A: LD_reg_reg(E, D); break;
		case 0x5B: LD_reg_reg(E, E); break;
		case 0x5C: LD_reg_reg(E, H); break;
		case 0x5D: LD_reg_reg(E, L); break;
		case 0x5E: LD_reg_HLm(E); break;
		case 0x5F: LD_reg_reg(E, A); break;
		case 0x60: LD_reg_reg(H, B); break;
		case 0x61: LD_reg_reg(H, C); break;
		case 0x62: LD_reg_reg(H, D); break;
		case 0x63: LD_reg_reg(H, E); break;
		case 0x64: LD_reg_reg(H, H); break;
		case 0x65: LD_reg_reg(H, L); break;
		case 0x66: LD_reg_HLm(H); break;
		case 0x67: LD_reg_reg(H, A); break;
		case 0x68: LD_reg_reg(L, B); break;
		case 0x69: LD_reg_reg(L, C); break;
		case 0x6A: LD_reg_reg(L, D); break;
		case 0x6B: LD_reg_reg(L, E); break;
		case 0x6C: LD_reg_reg(L, H); break;
		case 0x6D: LD_reg_reg(L, L); break;
		case 0x6E: LD_reg_HLm(L); break;
		case 0x6F: LD_reg_reg(L, A); break;
		case 0x70: LD_HLm_reg(B); break;
		case 0x71: LD_HLm_reg(C); break;
		case 0x72: LD_HLm_reg(D); break;
		case 0x73: LD_HLm_reg(E); break;
		case 0x74: LD_HLm_reg(H); break;
		case 0x75: LD_HLm_reg(L); break;
		
		case 0x77: LD_HLm_reg(A); break;
		case 0x78: LD_reg_reg(A, B); break;
		case 0x79: LD_reg_reg(A, C); break;
		case 0x7A: LD_reg_reg(A, D); break;
		case 0x7B: LD_reg_reg(A, E); break;
		case 0x7C: LD_reg_reg(A, H); break;
		case 0x7D: LD_reg_reg(A, L); break;
		case 0x7E: LD_reg_HLm(A); break;
		case 0x7F: LD_reg_reg(A, A); break;
		
	}
}

void LD_reg_reg(byte reg1, byte reg2) {
	assert(reg1 <= L && reg2 <= L);
	regs8[reg1]=regs8[reg2];
	regs8[M] += 1;
}

void LD_HLm_reg(byte reg) {
	assert(reg <= L);
	wb((regs8[L]<<8)+regs8[H], regs8[reg]);
	regs8[M] += 2;
}

void LD_reg_HLm(byte reg) {
	assert(reg <= L);
	regs8[reg] = rb((regs8[L] << 8) + regs8[H]);
	regs8[M] += 2;
}

void LD_reg16_lit(byte reg16) {
	assert(reg16 >= SP && reg16 <= HL);
	switch (reg16) {
		case SP: regs16[SP] = rw(regs16[PC]+1); break;
		case BC: regs8[C] = rb(regs16[PC]); regs8[B] = rb(regs16[PC]+1); break;
		case DE: regs8[D] = rb(regs16[PC]); regs8[E] = rb(regs16[PC]+1); break;
		case HL: regs8[H] = rb(regs16[PC]); regs8[L] = rb(regs16[PC]+1); break;
	}
	regs16[PC] += 2;
	regs8[M] += 3;
}

void LD_reg_lit(byte reg) {
	assert(reg <= L);
	switch (reg) {
		case A: regs8[A] = rb(regs16[PC]); break;
		case B: regs8[B] = rb(regs16[PC]); break;
		case C: regs8[C] = rb(regs16[PC]); break;
		case D: regs8[D] = rb(regs16[PC]); break;
		case E: regs8[E] = rb(regs16[PC]); break;
		case H: regs8[H] = rb(regs16[PC]); break;
		case L: regs8[L] = rb(regs16[PC]); break;
	}
	regs16[PC]++;
	regs8[M] +=2;
}

void nop() { regs8[M] += 1; }



